package com.cq.hd.order.factory;

import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.response.Throw;
import com.cq.hd.member.api.TbBusinessAgentApi;
import com.cq.hd.member.api.TbBusinessApi;
import com.cq.hd.member.api.TbBusinessPointsMallApi;
import com.cq.hd.member.api.TbConfigSettingApi;
import com.cq.hd.member.api.vo.BusinessPageVo;
import com.cq.hd.member.api.vo.BusinessPointsMallProductVo;
import com.cq.hd.member.api.vo.BusinessPointsMallSettingsVo;
import com.cq.hd.order.api.dto.CreateOrderDto;
import com.cq.hd.order.api.dto.OrderCommissionDto;
import com.cq.hd.order.api.vo.CreateOrderVo;
import com.cq.hd.product.api.TbActiveAgentApi;
import com.cq.hd.product.api.TbActiveRedPacketBillApi;
import com.cq.hd.product.api.TbActiveShareApi;
import com.cq.hd.product.api.vo.ActiveRedPacketBillPageVo;
import com.cq.hd.product.api.vo.ActiveShareRecordVo;
import com.cq.hd.product.api.vo.ActiveVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
public abstract class AbstractOrderHandler {
    @Autowired
    private TbActiveShareApi activeShareApi;

    @Autowired
    private TbBusinessAgentApi businessAgentApi;

    @Autowired
    private TbActiveAgentApi activeAgentApi;

    @Autowired
    private TbActiveRedPacketBillApi activeRedPacketBillApi;

    @Autowired
    private TbBusinessApi businessApi;

    @Autowired
    private TbBusinessPointsMallApi tbBusinessPointsMallApi;

    @Autowired
    private TbConfigSettingApi configSettingApi;

    @PostConstruct
    public void init() {
        OrderFactory.register(getType(), this);
    }

    protected abstract Integer getType();

    public abstract CreateOrderVo createOrder(CreateOrderDto createOrderDto, ActiveVo activeVo);

    public abstract CreateOrderVo createPointsOrder(CreateOrderDto createOrderDto, BusinessPointsMallProductVo productVo);

    // 获取商家积分商城配置
    public BusinessPointsMallSettingsVo getPointsMallSettings(Long businessId) {
        BusinessPointsMallSettingsVo pointsMallSettingsVo = new BusinessPointsMallSettingsVo();

        BusinessPageVo businessPageVo = businessApi.getById(businessId).unpack();
        if (businessPageVo == null || !businessPageVo.getPointsMallState().equals(BusinessPointsMallStateEnum.OPEN.getValue())) {
            return pointsMallSettingsVo;
        }

        return tbBusinessPointsMallApi.getSettings(businessId).unpack();
    }

    // 计算一级经纪人，二级经纪人可得佣金
    public OrderCommissionDto calOrderCommission(OrderCommissionDto orderCommissionDto, ActiveVo activeVo, BigDecimal distributionPointsRate) {
        String code = orderCommissionDto.getCode();
        if (StringUtils.isEmpty(code)) {
            return orderCommissionDto;
        }
        Long activeId = activeVo.getId();
        Long userId = orderCommissionDto.getUserId();
        BigDecimal orderPrice = orderCommissionDto.getOrderPrice();
        BigDecimal payPrice = orderCommissionDto.getPayPrice();
        Integer orderNum = orderCommissionDto.getOrderNum();

        // 分销开启状态(1-关闭，2-开启)
        if (activeVo.getAgentState().equals(AgentStateEnum.CLOSE.getValue())) {
            return orderCommissionDto;
        }

        // 没找到分享码，直接返回
        ActiveShareRecordVo activeShareRecordVo = activeShareApi.getByCode(code, activeId).unpack();
        if (activeShareRecordVo == null || activeShareRecordVo.getDelState() != 0) {
            return orderCommissionDto;
        }
        // 推广奖励类型（0-无，1-佣金，2-其他权益，3-积分）
        // 奖励类型改成从活动获取
        Integer rewardType = activeVo.getRewardType();
        if (rewardType == null || rewardType == 0) {
            return orderCommissionDto;
        }

        // 如果是经纪人分享给自己下单，也不会有佣金/权益
        if (activeShareRecordVo.getUserId().equals(userId)) {
            return orderCommissionDto;
        }

        Long businessId = activeVo.getBusinessId();         // 商家id
        Long agent1Id = activeShareRecordVo.getAgent1Id();  // 一级经纪人id
        Long agent2Id = activeShareRecordVo.getAgent2Id();  // 二级经纪人id，如果有
        if (agent1Id == null || agent1Id <= 0) {
            return orderCommissionDto;
        }

        // 获取商家跟一级经纪人的佣金比例
        BigDecimal exclusiveCommissionRate = businessAgentApi.getAgentCommissionRate(agent1Id, businessId).unpack();
        if (exclusiveCommissionRate == null || exclusiveCommissionRate.compareTo(BigDecimal.ZERO) < 0) {
            return orderCommissionDto;
        }

        // 是否是所有经纪人可推广：1-是，2-否，如果不是所有经纪人可推广，需要获取活动可推广经纪人出来判断
        if (AgentNumStateEnum.NO.getValue().equals(activeVo.getAgentNumState())) {
            // 查询活动分销经纪人列表
            List<Long> agentIds = activeAgentApi.listByActiveId(activeId).unpack();

            // 判断一级经纪人是否具备分佣权限
            if (CollectionUtils.isEmpty(agentIds) || !agentIds.contains(agent1Id)) {
                return orderCommissionDto;
            }
        }

        // 如果有二级经纪人，需要判断是否有绑定关系及佣金
        BigDecimal subAgentCommissionRate = BigDecimal.ZERO;
        if (agent2Id != null && agent2Id > 0) {
            subAgentCommissionRate = businessAgentApi.getSubAgentCommissionRate(agent2Id, agent1Id).unpack();

            // 没有设置二级佣金，则取默认二级佣金比例
            if (subAgentCommissionRate == null || subAgentCommissionRate.compareTo(BigDecimal.ZERO) == 0) {
                // 获取默认二级佣金比例
                String defaultLevel2CommissionRate = configSettingApi.getUserConfigValue(
                        agent1Id, ConfigSettingKeyEnum.DEFAULT_LEVEL2_COMMISSION_RATE.name()).unpack();
                if (StringUtils.isEmpty(defaultLevel2CommissionRate)) {
                    return orderCommissionDto;
                } else {
                    subAgentCommissionRate = new BigDecimal(defaultLevel2CommissionRate);
                }
            } else if (subAgentCommissionRate.compareTo(BigDecimal.ZERO) < 0) {
                return orderCommissionDto;
            }
        }

        orderCommissionDto.setRewardType(rewardType);
        orderCommissionDto.setAgent1Id(agent1Id);
        orderCommissionDto.setAgent2Id(agent2Id);
        // 经纪人选择推广奖励是其他权益
        if (rewardType == 2) {
            orderCommissionDto.setOtherEquity(activeVo.getOtherEquity());
            return orderCommissionDto;
        }

        // 经纪人选择推广奖励是佣金，则需要查该经纪人的专属佣金数据
        BigDecimal actualCommissionAmt = BigDecimal.ZERO;
        BigDecimal subAgentCommissionAmt = BigDecimal.ZERO;
        if (rewardType.equals(RewardTypeEnum.COMMISSION.getValue())) {
            if (exclusiveCommissionRate.compareTo(BigDecimal.ZERO) > 0) {
                orderCommissionDto.setCalCommissionType(CalCommissionTypeEnum.EXCLUSIVE_COMMISSION.getValue());
                orderCommissionDto.setExclusiveCommissionRate(exclusiveCommissionRate);
                // 实际全核销佣金金额=售价*专属佣金比例
                actualCommissionAmt = orderPrice.multiply(exclusiveCommissionRate).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
            } else {
                // 默认佣金类型：0-无，1-佣金，2-佣金比例
                Integer defaultCommissionType = activeVo.getDefaultCommissionType();
                if (defaultCommissionType == null || defaultCommissionType.equals(DefaultCommissionTypeEnum.NULL.getValue())) {
                    return orderCommissionDto;
                }

                if (DefaultCommissionTypeEnum.COMMISSION.getValue().equals(defaultCommissionType)) {
                    orderCommissionDto.setCalCommissionType(CalCommissionTypeEnum.FIX_COMMISSION.getValue());
                    // 实际全核销佣金金额=固定佣金*下单数量
                    actualCommissionAmt = activeVo.getCommissionAmt().multiply(new BigDecimal(String.valueOf(orderNum)));
                } else if (DefaultCommissionTypeEnum.COMMISSION_RATE.getValue().equals(defaultCommissionType)) {
                    orderCommissionDto.setCalCommissionType(CalCommissionTypeEnum.FIX_COMMISSION_RATE.getValue());
                    // 实际全核销佣金金额=售价*固定佣金比例
                    actualCommissionAmt = orderPrice.multiply(activeVo.getCommissionRate()).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
                }
            }

            // 判断实付金额是否小于全核销佣金，如果小于，则全核销佣金=实付金额
            if (payPrice.compareTo(actualCommissionAmt) < 0) {
                actualCommissionAmt = payPrice;
            }
            subAgentCommissionAmt = subAgentCommissionRate.multiply(actualCommissionAmt).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN);
        }


        // 如果选择的是积分，需要换算一下
        BigDecimal agentPointsAmt = BigDecimal.ZERO;
        BigDecimal subAgentPointsAmt = BigDecimal.ZERO;


        if (rewardType.equals(RewardTypeEnum.POINTS.getValue())) {
            actualCommissionAmt = BigDecimal.ZERO;
            subAgentCommissionAmt = BigDecimal.ZERO;
            if (agent2Id != null && agent2Id > 0) {
                agentPointsAmt = Optional.ofNullable(activeVo.getRewardPoints()).orElse(BigDecimal.ZERO);
                subAgentPointsAmt = subAgentCommissionRate.multiply(agentPointsAmt).divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_DOWN);
//                subAgentPointsAmt = subAgentCommissionAmt.multiply(distributionPointsRate);
//                actualCommissionAmt = actualCommissionAmt.subtract(subAgentCommissionAmt);
//                subAgentCommissionAmt = BigDecimal.ZERO;
            } else {
                agentPointsAmt = Optional.ofNullable(activeVo.getRewardPoints()).orElse(BigDecimal.ZERO);
//                agentPointsAmt = actualCommissionAmt.multiply(distributionPointsRate);
//                actualCommissionAmt = BigDecimal.ZERO;
            }
        }

        orderCommissionDto.setActualCommissionAmt(actualCommissionAmt);
        orderCommissionDto.setSubAgentCommissionRate(subAgentCommissionRate);
        orderCommissionDto.setSubAgentCommissionAmt(subAgentCommissionAmt);
        orderCommissionDto.setAgentPointsAmt(agentPointsAmt);
        orderCommissionDto.setSubAgentPointsAmt(subAgentPointsAmt);
        log.error("orderCommissionDto: {}", orderCommissionDto);

        return orderCommissionDto;
    }

    public ActiveRedPacketBillPageVo getRedPacketBill(Long redPacketBillId, Long userId, Long activeId, Integer totalOrderCount, BigDecimal orderPrice) {
        if (redPacketBillId == null || redPacketBillId <= 0) {
            return null;
        }

        ActiveRedPacketBillPageVo activeRedPacketBillPageVo = activeRedPacketBillApi.getById(redPacketBillId).unpack();
        if (activeRedPacketBillPageVo == null || !Objects.equals(activeRedPacketBillPageVo.getUserId(), userId)) {
            Throw.isBusinessException("未找到红包数据");
        }

        // 判断红包是否可以在该活动使用
        Long getActiveId = activeRedPacketBillPageVo.getActiveId();
        if (getActiveId > 0 && !activeId.equals(getActiveId)) {
            Throw.isBusinessException("红包不能用于该活动");
        }

        // 能否使用新用户红包
        Integer redPacketType = activeRedPacketBillPageVo.getRedPacketType();
        if (redPacketType.equals(RedPacketTypeEnum.NEW_USER.getValue())) {
            if (totalOrderCount != null && totalOrderCount > 0) {
                Throw.isBusinessException("你已经不是新用户，无法使用新用户红包");
            }
        }

        // 是否达到满减金额
        BigDecimal fullAmount = activeRedPacketBillPageVo.getFullAmount();
        if (fullAmount != null && fullAmount.compareTo(BigDecimal.ZERO) > 0) {
            if (orderPrice.compareTo(fullAmount) < 0) {
                Throw.isBusinessException("订单金额未达到该红包的使用门槛金额【" + fullAmount.stripTrailingZeros().toPlainString() + "元】");
            }
        }

        // 判断是否已被使用
        Integer state = activeRedPacketBillPageVo.getState();
        if (ActiveRedPacketStateEnum.YES_UES.getValue().equals(state) || ActiveRedPacketStateEnum.YES_VERIFY.getValue().equals(state)) {
            Throw.isBusinessException("红包已被使用");
        }

        // 判断是否已过期
        if (ActiveRedPacketStateEnum.YES_EXPIRE.getValue().equals(state)) {
            Throw.isBusinessException("红包已过期");
        }

        LocalDateTime now = LocalDateTime.now();
        LocalDateTime expireTime = activeRedPacketBillPageVo.getExpireTime();
        if (now.compareTo(expireTime) >= 0) {
            Throw.isBusinessException("红包已过期");
        }

        activeRedPacketBillPageVo.setState(ActiveRedPacketStateEnum.YES_UES.getValue());
        activeRedPacketBillPageVo.setUseTime(now);

        return activeRedPacketBillPageVo;
    }
}
